﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Timers;
using System.Web;
using TeamCityMonitor.Repository.Caches;
using TeamCitySharp.DomainEntities;
using File = System.IO.File;

namespace TeamCityMonitor.Repository
{
    public interface IUserPictureRepository
    {
        string GetUserPicture(string username);
    }

    public class UserPictureRepository : IUserPictureRepository
    {
        private static string defaultPictureUrl;
        private static string downloadLocalUrl;
        private static Timer refreshLocalPicturesTimer;
        private static Dictionary<string, string> userPictureDictionary;

        static UserPictureRepository()
        {
            downloadLocalUrl = HttpContext.Current.Server.MapPath("~/Content/userpictures");
            defaultPictureUrl = string.Format("../../Content/userpictures/{0}", (Properties.Settings.Default.DefaultProfilePicture ?? "unknown-user-profile.jpg"));

            userPictureDictionary = new Dictionary<string, string>();

            LoadCurrentUserPictures(); 

            refreshLocalPicturesTimer = new Timer();
            refreshLocalPicturesTimer.Elapsed += RefreshLocalPicturesTimerOnElapsed;
            refreshLocalPicturesTimer.Interval = 60000;
            refreshLocalPicturesTimer.Start();
        }

        private static void LoadCurrentUserPictures()
        {
            try
            {
                var files = Directory.GetFiles(downloadLocalUrl);
                files.ToList()
                    .ForEach(file =>
                    {
                        var user = new User { Username = Path.GetFileNameWithoutExtension(file) };
                        userPictureDictionary.Add(user.Username, GetRelativePathToUserPicture(user));
                    });
            }
            catch(Exception e)
            {
                log4net.LogManager.GetLogger("UserRepository").Error("Error loading files on startup.", e);
            }
        }

        private static void RefreshLocalPicturesTimerOnElapsed(object sender, ElapsedEventArgs elapsedEventArgs)
        {
            refreshLocalPicturesTimer.Stop();

            try
            {
                var users = new TeamCityRepository(new UserPictureRepository()).GetUsers().ToList();

                users.Where(user => userPictureDictionary.ContainsKey(user.Username) == false || userPictureDictionary[user.Username] == defaultPictureUrl).ToList()
                        .ForEach(DownloadUserPicture);

                users.ForEach(UpdateDictionary);
            }
            finally
            {
                refreshLocalPicturesTimer.Start();
            }
        }

        private static void UpdateDictionary(User user)
        {
            var picture = (CheckIsUserPictureExists(user) == true 
                               ? GetRelativePathToUserPicture(user)
                               : defaultPictureUrl);

            if(userPictureDictionary.ContainsKey(user.Username) == false)
            {
                userPictureDictionary.Add(user.Username, picture);
            }
            else
            {
                userPictureDictionary[user.Username] = picture;
            }
        }

        private static bool CheckIsUserPictureExists(User user)
        {
            var localUrl = GetUserPictureLocalUrl(user);
            return (localUrl.Contains("NOUSERNAME") == true ? false : File.Exists(localUrl));
        }

        private static string GetUserPictureUrl(User user)
        {
            return string.Format(Properties.Settings.Default.UsernamePictureUrl, (user.Username ?? "NOUSERNAME"));
        }

        private static string GetUserPictureLocalUrl(User user)
        {
            return Path.Combine(downloadLocalUrl, Path.GetFileName(GetUserPictureUrl(user)));
        }

        private static void DownloadUserPicture(User user)
        {
            try
            {
                var pictureUrl = GetUserPictureUrl(user);
                using (var client = new WebClient())
                {
                    client.Credentials = CredentialCache.DefaultCredentials;
                    client.DownloadData(pictureUrl);
                    client.DownloadFile(pictureUrl, GetUserPictureLocalUrl(user));
                }
            }
            catch (Exception e)
            {
                log4net.LogManager.GetLogger("UserRepository").ErrorFormat("Unable to download picture from {0} (user={1}) to {2}.\r\n{3}",
                    (Properties.Settings.Default.UsernamePictureUrl ?? ""),
                    (user.Username ?? ""),
                    downloadLocalUrl,
                    e.Message);
            }
        }

        public string GetUserPicture(string username)
        {
            return userPictureDictionary.ContainsKey(username) ? userPictureDictionary[username] : defaultPictureUrl;
        }

        private static string GetRelativePathToUserPicture(User user)
        {
            return string.Format("../../Content/userpictures/{0}", Path.GetFileName(GetUserPictureUrl(user)));
        }
    }
}